package de.tudarmstadt.fgbs.cafe.importexport;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import de.tudarmstadt.fgbs.cafe.exception.FlawedConfigurationException;
import de.tudarmstadt.fgbs.cafe.structure.Bahnhof;
import de.tudarmstadt.fgbs.cafe.structure.Fahrplan;
import de.tudarmstadt.fgbs.cafe.structure.Wegpunkt;
import de.tudarmstadt.fgbs.cafe.structure.Zuglauf;

/**
 * Class for exporting the data to a file
 * 
 * @author Christian Schlehuber
 * 
 */
public class ExportAgent implements ExportInterface {

    private static String fileExtension = ".fpl";

    private final static String commentMark = "#";
    private final static String lineRuler = "####################################";

    /**
     * The log which is used to log all behaviors of this class.
     */
    private static Log LOG = LogFactory.getLog(ExportAgent.class);

    // Interface for accessing other methods of the system for fulfilling the
    // export tasks
    /**
     * Interface for the functionalities of the core system
     */
    private ExportCoreInterface core;

    /**
     * Constructor of the ExportAgent
     * 
     * @param core
     *            a reference to an class, which provides the needed core
     *            interfaces
     * @see ExportCoreInterface
     */
    public ExportAgent(ExportCoreInterface core) {
	if (LOG.isTraceEnabled())
	    LOG.trace("# a new instance of ExportAgent is created");
	this.core = core;
    }

    @Override
    public boolean exportFPL(int fplID, String name, String location) {
	if (LOG.isTraceEnabled())
	    LOG.trace("# ExportAgent.exportFPL(" + fplID + ", " + name + ", "
		    + location + ")");
	try {
	    Fahrplan exportFPL = core.retrieveFPL(fplID);

	    // add file extension, if not already set
	    if (!name.toLowerCase().endsWith(fileExtension))
		name += fileExtension;

	    FileWriter fw = new FileWriter(location + File.separator + name);
	    BufferedWriter writer = new BufferedWriter(fw);
	    writeFPLHeader(exportFPL, writer);
	    for (Iterator<Zuglauf> it = exportFPL.getZuglaeufe().iterator(); it
		    .hasNext();) {
		exportZL(it.next(), writer);
	    }
	    writer.flush();
	    writer.close();
	    return true;
	} catch (IOException e) {
	    LOG.error("# an IO exception occured: " + e.getMessage());
	} catch (FlawedConfigurationException e) {
	    LOG.error("# a configuration exception occured: " + e.getMessage());
	}
	return false;
    }

    @Override
    public boolean exportFPL(Fahrplan fpl, String name, String absolutePath) {
	if (LOG.isTraceEnabled())
	    LOG.trace("# ExportAgent.exportFPL(" + fpl.toString() + ", " + name
		    + ", " + absolutePath + ")");
	try {
	    // add file extension, if not already set
	    if (!name.toLowerCase().endsWith(fileExtension))
		name += fileExtension;

	    FileWriter fw = new FileWriter(absolutePath + File.separator + name);
	    BufferedWriter writer = new BufferedWriter(fw);
	    writeFPLHeader(fpl, writer);
	    for (Iterator<Zuglauf> it = fpl.getZuglaeufe().iterator(); it
		    .hasNext();) {
		exportZL(it.next(), writer);
	    }
	    writer.flush();
	    writer.close();
	    return true;
	} catch (IOException e) {
	    LOG.error("# an IO exception occured: " + e.getMessage());
	}
	return false;
    }

    private void writeFPLHeader(Fahrplan fpl, BufferedWriter writer)
	    throws IOException {
	if (LOG.isTraceEnabled())
	    LOG.trace("# ExportAgent.writeFPLHeader(" + fpl.toString() + ", "
		    + writer.toString() + ")");
	Date currentTime = new Date();
	String currentTimeString = DateFormat.getDateInstance(DateFormat.FULL,
		Locale.GERMAN).format(currentTime);
	writer.write(ExportAgent.lineRuler + "\n");
	writer.write(ExportAgent.commentMark + "Fahrplan: " + fpl.getName()
		+ "\n");
	writer.write(ExportAgent.commentMark + "Revision: " + fpl.getRevision()
		+ "\n");
	writer.write(ExportAgent.commentMark + "Written: " + currentTimeString
		+ "\n");
	writer.write(ExportAgent.commentMark + "Editor: CaFE V0.4" + "\n");
	writer.write(ExportAgent.commentMark + "Type: Export" + "\n");
	writer.write(ExportAgent.lineRuler + "\n");
    }

    private void exportZL(Zuglauf zuglauf, BufferedWriter writer)
	    throws IOException {
	if (LOG.isTraceEnabled())
	    LOG.trace("# ExportAgent.exportZL(" + zuglauf.toString() + ", "
		    + writer.toString() + ")");
	exportZLHeader(zuglauf, writer);
	exportZLStations(zuglauf, writer);
    }

    private void exportZLStations(Zuglauf zuglauf, BufferedWriter writer)
	    throws IOException {
	if (LOG.isTraceEnabled())
	    LOG.trace("# ExportAgent.exportZLStations(" + zuglauf.toString()
		    + ", " + writer.toString() + ")");
	List<Wegpunkt> wegpunkte = zuglauf.getStationen();
	Wegpunkt previous = new Wegpunkt();
	for (Iterator<Wegpunkt> it = wegpunkte.iterator(); it.hasNext();) {
	    Wegpunkt current = it.next();
	    if (current.getBahnhof().getHaltepunkt() != null
		    && !current.isDurchfahrt()) {
		Bahnhof hp = current.getBahnhof().getHaltepunkt();
		if (hp.hasNeighbor(previous.getBahnhof())) {
		    // Erst den HP exportieren
		    Wegpunkt wpHp = new Wegpunkt(hp, current.getAnkunft(),
			    current.getAbfahrt(), current.getRegelgleis(),
			    current.isWende(), current.isDurchfahrt());
		    writer.write(wpHp.exportForFPL() + "\n");
		    // dann den Wegpunkt
		    current.setAnkunft(wpHp.getAbfahrt());
		    current.setAbfahrt(wpHp.getAbfahrt());
		    current.setDurchfahrt(true);
		    writer.write(current.exportForFPL() + "\n");
		} else {
		    Wegpunkt wpHp = new Wegpunkt(hp, current.getAnkunft(),
			    current.getAbfahrt(), current.getRegelgleis(),
			    current.isWende(), current.isDurchfahrt());
		    current.setAnkunft(wpHp.getAnkunft());
		    current.setAbfahrt(wpHp.getAnkunft());
		    // Erst den Wegpunkt exportieren
		    current.setDurchfahrt(true);
		    writer.write(current.exportForFPL() + "\n");
		    // dann den Haltepunkt
		    writer.write(wpHp.exportForFPL() + "\n");
		}
	    } else {
		writer.write(current.exportForFPL() + "\n");
	    }
	    previous = current;
	}
    }

    private void exportZLHeader(Zuglauf zuglauf, BufferedWriter writer)
	    throws IOException {
	if (LOG.isTraceEnabled())
	    LOG.trace("# ExportAgent.exportZLHeader(" + zuglauf.toString()
		    + ", " + writer.toString() + ")");
	boolean ausWende = zuglauf.getStationen().get(0).isWende();
	boolean aufWende = zuglauf.getStationen()
		.get(zuglauf.getStationen().size() - 1).isWende();
	String isWende = "0";
	String isFahrbereit = "0";
	String isPersonenZug = "0";

	String fromString = "Kommt aus";
	String toString = "Weiter als";
	if (ausWende)
	    fromString = "Wende aus";
	if (aufWende)
	    toString = "Wende auf";
	if (zuglauf.isWende())
	    isWende = "1";
	if (zuglauf.isReady())
	    isFahrbereit = "1";
	if (zuglauf.isPersonenZug())
	    isPersonenZug = "1";
	writer.write("Zugnummer:\t" + zuglauf.getGattung()
		+ zuglauf.getNumber() + "\n");
	writer.write("Baureihe:\t" + zuglauf.getBaureihe() + "\n");
	writer.write("Betriebstage:\tXXXXXXX\n");
	writer.write("Fahrbereit:\t" + isFahrbereit + "\n");
	writer.write("Personenzug:\t" + isPersonenZug + "\n");
	writer.write("Plus:\t" + zuglauf.getPlus() + "\n");
	writer.write("Umlauf:\t" + zuglauf.getUmlauf() + "\n");
	writer.write("Vmax:\t" + zuglauf.getVmax() + "\n");
	writer.write("Wendezug:\t" + isWende + "\n");
	if (zuglauf.getKommtAusNr() != "")
	    writer.write(fromString + ":\t" + zuglauf.getKommtAusNr() + "\n");
	if (zuglauf.getWirdZuNr() != "")
	    writer.write(toString + ":\t" + zuglauf.getWirdZuNr() + "\n");
    }

}
